package com.glodon.paas.document.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.glodon.paas.account.api.bean.Communicate;
import com.glodon.paas.account.api.bean.User;
import com.glodon.paas.document.api.bean.File;
import com.glodon.paas.document.api.bean.PublicToken;
import com.glodon.paas.document.api.bean.Share;
import com.glodon.paas.document.biz.FileBiz;
import com.glodon.paas.document.biz.ShareBiz;
import com.glodon.paas.document.constant.DocumentConstant;
import com.glodon.paas.document.dao.domain.FileInfoEntity;
import com.glodon.paas.document.dao.domain.PublicTokenEntity;
import com.glodon.paas.document.dao.domain.ShareEntity;
import com.glodon.paas.document.service.ShareService;
import com.glodon.paas.document.service.util.DocumentPrivilege;
import com.glodon.paas.document.service.util.OrderUtilsFile;
import com.glodon.paas.document.service.util.WebService;
import com.glodon.paas.dto.DataTansitionObject;
import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.glodon.paas.mail.MailClient;
import com.glodon.paas.mail.MailMessageParam;
import com.glodon.paas.util.StringUtil;

@Service("shareService")
public class ShareServiceImpl implements ShareService {

    private static final Logger LOGGER    = LoggerFactory.getLogger(ShareServiceImpl.class);

    @Autowired
    private ShareBiz            shareBiz;

    @Autowired
    private FileBiz             fileBiz;

    @Autowired
    private MailClient          mailClient;
    
    @Autowired
    private WebService webService;

    @Value("${document.shareNewUser.email.subject}")
    private String              mailSubject;
    @Value("${document.shareNewUser.email.send2Admin}")
    private boolean             sendAdmin = true;
    @Value("${document.shareNewUser.email.adminEmail}")
    private String              adminEmail;
    @Value("${document.shareNewUser.email.targetUrl}")
    private String              targetUrl;

    @Autowired
    private DocumentPrivilege   privilege;

    @Override
    public List<Share> getSharesByMe(String userId) {
        return ShareEntity.getDtos(shareBiz.getSharesByMe(userId, null, DocumentConstant.SHARE_TYPE_SHARED));
    }

    @Override
    public List<Share> getSharesForMe(String userId) {
        return ShareEntity.getDtos(shareBiz.getSharesForMe(userId, null));
    }

    @Override
    public List<Share> getPublicShares(String userId) {
        return ShareEntity.getDtos(shareBiz.getSharesByMe(userId, null, DocumentConstant.SHARE_TYPE_PUBLISHED));
    }

    /**
     *@see com.glodon.paas.document.service.ShareService#getSharesOnFile(String userId, String fileId, boolean includePath)
     */
    public List<ShareEntity> getSharesOnFile(String userId, String fileId, boolean includePath){
       List<ShareEntity> shareList4Return = new ArrayList<ShareEntity>();
        
       FileInfoEntity file = fileBiz.getFile(fileId);
       if(file == null){
           throw PaasServerExceptionFactory.notFoundException("can not find file[" + fileId + "]", null);
       }
       
       if(!includePath){
           if(file.isShared()){
               return shareBiz.getSharesByMe(userId, fileId, null);
           }else{
               return shareList4Return;
           }
       }
       
       List<FileInfoEntity> fileList = fileBiz.getParents(file);
       fileList.add(file);
       
       // 获取文件路径上所有共享信息
       for (FileInfoEntity item : fileList) {
           if(item.isShared()){
               List<ShareEntity> shares = shareBiz.getSharesByMe(userId, item.getId(), null);
               shareList4Return.addAll(shares);
           }
       }
        return shareList4Return;
    }
    
    @Override
    public List<File> getFilesByShares(List<Share> shares, String orderBy, String orderType, boolean cascade) {
        if (shares != null && shares.size() > 0) {
            List<FileInfoEntity> files = new ArrayList<FileInfoEntity>();
            Set<String> fileIds = new HashSet<String>();
            for (Share se : shares) {
                String fileId = se.getFileId();
                if (!fileIds.contains(fileId)) {
                    FileInfoEntity file = fileBiz.getNormalFile(fileId);
                    files.add(file);
                    fileIds.add(fileId);
                }
            }
            List<File> res = FileInfoEntity.getDtos(files, cascade);
            if (StringUtils.isNotBlank(orderBy)) {
                OrderUtilsFile.order(res, orderBy, orderType);
            }
            return res;
        }
        return new ArrayList<File>();
    }

    @Override
    public void cancelShare(String ownerId, String fileId, String toUserId) {
        privilege.checkWritePrivilege(ownerId, fileId, true, true);
        shareBiz.remove(toUserId, fileId);
        if (!shareBiz.isSharedFile(fileId)) {
            fileBiz.cancelShare(fileId);
        }
        LOGGER.debug("User[" + ownerId + "] canceled share file[" + fileId + "] for User[" + toUserId + "] success.");
    }

    @Override
    public void cancelShare(String userId, String fileId) {
        if (privilege.isFileSharer(userId, fileId)) {
            shareBiz.remove(userId, fileId);
        } else if (privilege.isFileOwner(userId, fileId)) {
            shareBiz.remove(fileId, DocumentConstant.SHARE_TYPE_SHARED);
        } else {
            throw PaasServerExceptionFactory.privilegeException("file[" + fileId + "] does not shared for user["
                                                                + userId + "]", null);
        }
        if (!shareBiz.isSharedFile(fileId)) {
            fileBiz.cancelShare(fileId);
        }
        LOGGER.debug("User[" + userId + "] canceled share file[" + fileId + "] success.");
    }

    @Override
    public List<User> getSharedUser(String userId, String fileId) {
        privilege.checkReadPrivilege(userId, fileId, true, true);
        List<ShareEntity> shares = shareBiz.getSharesByMe(userId, fileId, DocumentConstant.SHARE_TYPE_SHARED);
        if (shares != null && shares.size() > 0) {
            Set<String> userIds = new HashSet<String>();
            for (int i = 0; i < shares.size(); i++) {
                userIds.add(shares.get(i).getToUserId());
            }
            return webService.getUserByIds(userIds);
        }
        return new ArrayList<User>();
    }

    private void addRelationShip(String userId, String toUserId, String remarkName) {
        // 如果共享人不在联系人列表中，添加
        try {
            Communicate relationship = webService.queryCommunicateByContactId(userId, toUserId);
            if (relationship == null) {
                webService.addCommunicate(userId, toUserId, remarkName);
            }
        } catch (Exception e) {
            // do nothing
            LOGGER.error(e.getMessage());
        }
    }

    @Override
    public User shareFile(String userId, String fileId, String account, String sharePrivilege) {
        privilege.checkWritePrivilege(userId, fileId, true, true);
        if (StringUtils.isEmpty(account)) {
            throw PaasServerExceptionFactory.validateException("Email/Mobile/Id is empty.", null);
        }
        User toUser = webService.getUser(account);
        if (toUser == null) {
            toUser = webService.getInactiveUser(account);
        }
        if (toUser != null) {
            shareBiz.share(userId, fileId, toUser.getId(), sharePrivilege);
            fileBiz.shareFile(fileId);
        } else if (StringUtil.isEmail(account)) {
            toUser = webService.createInactiveUser(account);
            shareBiz.share(userId, fileId, toUser.getId(), sharePrivilege);
            FileInfoEntity file = fileBiz.shareFile(fileId);
            User sendUser = webService.getUser(userId);
            this.sendShareDocMailToAbsentUser(sendUser, toUser, file, targetUrl + "?userId=" + toUser.getId()
                                                                      + "&email=" + account);
            LOGGER.info("send a mail to [" + account + "] success!");
        } else {
            throw PaasServerExceptionFactory.notFoundException("can not find user[" + account + "]", null);
        }
        LOGGER.info("shared a file for user[" + toUser.getId() + "] success.");
        addRelationShip(userId, toUser.getId(), toUser.getEmail());
        return toUser;
    }

    @Override
    public List<DataTansitionObject> getNavigationByMe(String rootId, String fileId) {
        List<DataTansitionObject> ns = new ArrayList<DataTansitionObject>();
        FileInfoEntity file = fileBiz.getNormalFile(fileId);
        while (file != null) {
            DataTansitionObject n = new DataTansitionObject();
            n.setId(file.getId());
            n.setName(file.getName());
            ns.add(0, n);
            if (StringUtils.isEmpty(file.getParentId())) {
                break;
            }
            if (StringUtils.isNotEmpty(rootId)) {
                if (file.getId().equals(rootId)) {
                    break;
                }
            } else if (shareBiz.getShareCount(file.getId()) > 0) {
                break;
            }

            file = fileBiz.getFile(file.getParentId());
        }
        return ns;
    }

    @Override
    public List<DataTansitionObject> getNavigationForMe(String userId, String fileId) {
        if (privilege.isFileSharer(userId, fileId)) {
            List<DataTansitionObject> ns = new ArrayList<DataTansitionObject>();
            FileInfoEntity file = fileBiz.getNormalFile(fileId);
            while (file != null) {
                DataTansitionObject n = new DataTansitionObject();
                n.setId(file.getId());
                n.setName(file.getName());
                ns.add(0, n);
                ShareEntity share;
                share = shareBiz.getShareForMe(userId, file.getId());
                if (share != null || StringUtils.isEmpty(file.getParentId())) {
                    break;
                } else {
                    file = fileBiz.getNormalFile(file.getParentId());
                }
            }
            return ns;
        } else {
            throw PaasServerExceptionFactory.privilegeException("file[" + fileId + "] does not shared for user["
                                                                + userId + "]", null);
        }
    }

    /**
     * 分享文档时，向不存在用户发送邮件 新用户可以以此邮箱来激活账户 如果以此邮箱直接注册会产生新用户 如果用户激活时，检测该邮箱已被注册，此用户必须使用新邮箱
     */
    public void sendShareDocMailToAbsentUser(User currentUser, User mailUser, FileInfoEntity file, String actionLink) {
        MailMessageParam mailContent = new MailMessageParam();
        mailContent.setSubject(mailSubject);
        mailContent.setTo(new String[] { mailUser.getEmail() });
        if (sendAdmin) {
            mailContent.setTo(new String[] { mailUser.getEmail(), adminEmail });
        }
        // 模板数据
        Map<String, Object> param = new HashMap<String, Object>();
        mailContent.setTemplateParam(param);
        param.put("userName", currentUser.getDisplayName());
        param.put("userEmail", currentUser.getEmail());
        if (StringUtils.isBlank(file.getExtension())) {
            param.put("docName", file.getName());
        } else {
            param.put("docName", file.getName() + "." + file.getExtension());
        }
        param.put("isFolder", file.isFolder());
        param.put("newUserEmail", mailUser.getEmail());
        param.put("newUserId", mailUser.getId());
        param.put("actionLink", actionLink);

        mailContent.setTemplateLocation("mailTemplate/document_shareDocMailForAbsentUser.vm");
        // mailSender.send(mailContent);
        mailClient.sendMail(mailContent, false);
    }

    @Override
    public String publish(String userId, String fileId) {
        privilege.checkWritePrivilege(userId, fileId, true, true);
        FileInfoEntity file = fileBiz.getNormalFile(fileId);
        String token = shareBiz.publish(userId, file);
        if (!file.isPublished()) {
            fileBiz.publishFile(fileId);
        }
        LOGGER.debug("publish file[id:" + fileId + "] success.");
        return token;
    }

    @Override
    public void cancelPublish(String userId, String fileId) {
        privilege.checkWritePrivilege(userId, fileId, true, true);
        FileInfoEntity file = fileBiz.getFile(fileId);
        if (file.isPublished()) {
            fileBiz.cancelPublish(fileId);
        }
        if (shareBiz.isPublishedFile(fileId)) {
            shareBiz.remove(fileId, DocumentConstant.SHARE_TYPE_PUBLISHED);
            shareBiz.removeToken(fileId);
        }
        if (StringUtils.isNotBlank(file.getDataBagId())) {
            webService.cancelPublicDataBag(file.getDataBagId());
        }
        LOGGER.debug("cancel publish file[id:" + fileId + "] success.");
    }

    @Override
    public PublicToken getPublicToken(String token) {
        return PublicTokenEntity.getDto(shareBiz.getPublishInfoByToken(token));
    }

    // @Override
    // public void buildPublicToken(List<File> files) {
    // if(files != null){
    // for(File file : files){
    // if(file.isPublished()){
    // PublicTokenEntity pt = shareBiz.getPublishInfoByFile(file.getId());
    // if(pt == null){
    // continue;
    // }
    // String token = pt.getToken();
    // HashMap<String, String> at = (HashMap<String, String>)file.getAttributes();
    // if(at == null){
    // at = new HashMap<String, String>();
    // file.setAttributes(at);
    // }
    // at.put(StringConst.PUBLIC_TOKEN, token);
    // }
    // }
    // }
    // }
}
